package blazingbubble.graphics.game;

import blazingbubble.game.Player;
import blazingbubble.graphics.IActivable;
import blazingbubble.game.command.GameCommandFactory;
import blazingbubble.network.game.strategy.IPlayerTeamJoinListener;
import moltencore.network.protocol.PlayerData;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Vector;

public class GameStartup extends JPanel implements IActivable, ActionListener, IGamePlayerActivityListener, IJoinGameListener, IPlayerTeamJoinListener {
	private JButton startGameButton;

	private Container displayArea;

	private Team[] teams;
	private Team idlers;
	private boolean hasTeams;
	private GameCommandFactory commandFactory;
	private blazingbubble.game.Game game;

	public GameStartup(Container displayArea, GameCommandFactory commandFactory, blazingbubble.game.Game game) {
		this.displayArea = displayArea;
		this.commandFactory = commandFactory;
		this.game = game;
		this.game.addPlayerActivityListener(this);
	}

	public void setup(int teamCount, int teamSize) {
		this.removeAll();
		//Create game gui
		startGameButton = new JButton("Start");
		startGameButton.addActionListener(this);
		add(startGameButton);

		if(teamSize == 1) {
			hasTeams = false;
			teams = new Team[1];
			teams[0] = new Team("Players", teamCount, 0, commandFactory, true);
			add(teams[0]);
		}
		else {
			hasTeams = true;
			teams = new Team[teamCount];
			for(int i = 0; i < teams.length; i++) {
				teams[i] = new Team("Team " + (i + 1), teamSize, i, commandFactory, false);
				add(teams[i]);
			}
		}

		idlers = new Team("Idlers", teamCount * teamSize, -1, commandFactory, false);
		if(teamSize > 1) {
			add(idlers);
		}
		this.updateUI();
	}

	@Override
	public void playerJoined(Player player) {
		removePlayer(player);
		if(player.getTeamIndex() == -1) {
			idlers.playerTakeNextFreeSlot(player);
		}
		else {
			if(hasTeams) {
				teams[player.getTeamIndex()].playerTakeSlot(player);
			}
			else {
				teams[0].playerTakeSlot(player);
			}
		}
	}

	private void removePlayer(Player player) {
		idlers.removePlayerIfExists(player);
		for(Team team : teams) {
			team.removePlayerIfExists(player);
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		commandFactory.getStartGame().start();
	}

	@Override
	public void activate() {
		displayArea.removeAll();
		displayArea.add(this);
		((JPanel) displayArea).updateUI();
	}

	@Override
	public void gameJoined(int teams, int teamSize) {
		setup(teams, teamSize);
	}

	@Override
	public void playerJoinedTeam(Player player) {
		removePlayer(player);
		if(player.getTeamIndex() == -1) {
			idlers.playerTakeNextFreeSlot(player);
		}
		else if(hasTeams) {
			teams[player.getTeamIndex()].playerTakeSlot(player);
		}
		else {
			teams[0].playerTakeSlot(player);
		}
	}

	private static class Team extends JPanel {
		private boolean swapIndices;
		private DefaultTableModel players;
		private static final String[] playerColumnNames = {
				"Player"};

		public Team(String teamCaption, int teamSize, int index, GameCommandFactory commandFactory, boolean swapIndices) {
			this.swapIndices = swapIndices;
			players = new DefaultTableModel(null, playerColumnNames) {
				@Override
				public boolean isCellEditable(int row, int column) {
					return false;
				}
			};
			add(new JLabel(teamCaption), BorderLayout.NORTH);
			JTable playerTable = new JTable(players);
			add(new JScrollPane(playerTable), BorderLayout.CENTER);
			playerTable.addMouseListener(new ClickWatcher(playerTable, index, commandFactory, swapIndices));
			for(int i = 0; i < teamSize; i++) {
				players.insertRow(i, new Vector());
			}
		}

		public void playerTakeSlot(Player player) {
			players.removeRow(swapIndices ? player.getTeamIndex() : player.getPositionIndex());
			players.insertRow(swapIndices ? player.getTeamIndex() : player.getPositionIndex(), new Object[]{player.getName()});
		}

		public void playerTakeNextFreeSlot(Player player) {
			for(int i = 0; i < players.getRowCount(); i++) {
				if(players.getValueAt(i, 0) == null) {
					players.removeRow(i);
					players.insertRow(i, new Object[] { player.getName() });
					break;
				}
			}
		}

		public void removePlayerIfExists(Player player) {
			for(int i = 0; i < players.getRowCount(); i++) {
				if(player.getName().equals(players.getValueAt(i, 0))) {
					players.removeRow(i);
					players.insertRow(i, new Vector());
					break;
				}
			}
		}

		private class ClickWatcher extends MouseAdapter {
			private GameCommandFactory commandFactory;
			private JTable table;
			private int index;
			private boolean swapIndices;

			public ClickWatcher(JTable table, int index, GameCommandFactory commandFactory, boolean swapIndices) {
				this.commandFactory = commandFactory;
				this.swapIndices = swapIndices;
				this.table = table;
				this.index = index;
			}

			@Override
			public void mouseClicked(MouseEvent e) {
				int slot = table.rowAtPoint(e.getPoint());
				if(table.getModel().getValueAt(slot, 0) == null) {
					commandFactory.getJoinTeam().setTeamIndex(swapIndices ? slot : index);
					commandFactory.getJoinTeam().setSlotIndex(swapIndices ? index : slot);
					commandFactory.getJoinTeam().join();
				}
			}
		}
	}
}
